from forest.resource import Resources, Resource, ValidationError
from forest.resources.common import translate_disk_name

class Raid(Resource):
    ''' Raid resources allow definition of soft raid devices to which partitions can be created on.

        An example of using a bootable soft raid along with partitions::

            resources:

            - $: raid
              device_name: md0  # boot
              level: 1
              components: ['sda2', 'sdb2']
              metadata: 1.1

            - $: raid
              device_name: md1  # swap
              level: 1
              components: ['sda3', 'sdb3']
              metadata: 1.1

            - $: raid
              device_name: md2  # root
              level: 1
              components: ['sda4', 'sdb4']
              metadata: 1.1

            - $: parition-table
              disk: [sda, sdb]
              partitions:
              - name: bios-boot
                type: primary
                size: 1
                flags:
                   bios_grub: True

              - name: boot
                type: primary
                size: 500
                fstype: non-fs
                flags:
                   raid: True

              - name: swap
                type: primary
                size: 1000
                fstype: non-fs
                flags:
                   raid: True

              - name: root
                type: primary
                size: grow
                fstype: non-fs
                flags:
                   raid: True

        .. describe: device_name

            Required. A name for the device.

        .. describe: level

            Required. The raid level.

        .. describe:: components

            Required. A list of component device names

        .. describe:: metadata

            Optional. The raid metadata version. (Default: 1.1)

    '''
    __register__ = "raid"

    def get_components(self):

        components = self.value.get('components')

        component_list = []
        for component in components:
            try:
                component_list.append(translate_disk_name(self.config, component))
            except Exception, e:
                print e
                raise
                #raise Exception("Invalid raid definition"+str(self.value))

        return component_list

    def get_id(self):
        return 'raid:' + self.value.get('name')

    def get_name(self):
        return self.value.get('name')

    def get_level(self):

        return str(self.value.get('level'))

    def get_metadata(self):
        m = self.value.get('metadata', None)
        if m is None:
            return m
        return str(m)

    #def get_device(self):
    #    return translate_disk_name(self.config, self.value.get('device'))

    def validate(self):
        valid_keys = ['name', 'level', 'metadata', 'components']

        for k in self.value.iterkeys():
            if k in valid_keys:
                continue
            raise ValidationError('Undefined raid option {}'.format(k))

        necessary_keys = ['name', 'level', 'components']

        for necessary in necessary_keys:
            if necessary in self.value:
                continue
            raise ValidationError('Missing mandatory raid option {}. Please specify it'.format(necessary))

        levels = ['0', '1', '10', '4', '5', '6', 'raid0', 'raid1', 'raid4',
                  'raid5', 'raid6', 'raid10', 'linear', 'stripe', 'multipath',
                  'mp', 'faulty', 'container']

        level_str = str(self.value.get('level'))
        level = level_str.lower()

        if level not in levels:
            raise ValidationError('Raid level must be one of: {0}. Not {1}'.format(levels, level_str))

        metadatas = ['0', '0.90', '1', '1.0', '1.1', '1.2', 'default', 'ddf', 'imsm']

        metadata = str(self.value.get('metadata', '1.1'))


        if metadata and metadata not in metadatas:
            raise ValidationError('Raid metadata, if specified, must be one of: {}'.format(metadatas))
